package fuzzy_system.fcl;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import net.sourceforge.jFuzzyLogic.rule.RuleExpression;
import net.sourceforge.jFuzzyLogic.rule.RuleTerm;
import net.sourceforge.jFuzzyLogic.ruleConnectionMethod.RuleConnectionMethodAndMin;

import fuzzy_system.database.Regras;
import fuzzy_system.database.Termos;
import fuzzy_system.database.Variaveis;
import fuzzy_system.database.DBAtaque.*;
import fuzzy_system.database.DBDefesa.*;



public class CreateFCL {
	
	public static String fileFolder = "fcl/";
	
	public static int AG_FUZZY = 0;
	public static int FUZZY = 1;
	
	public static void create(int tipo) throws IOException{
		createFCL("Ataque",tipo);
		createFCL("Defesa",tipo);
	}
	
	public static void createFCL(String nameTxt, int tipo) throws IOException{
		Object [] variaveis = null;
		Object [] termos = null;
		Object [] regras = null;

		if(nameTxt.equals("Ataque")){
			variaveis = VA.values();
			termos = TA.values();
			regras = RA.values();
			
		}
		if(nameTxt.equals("Defesa")){
			variaveis = VD.values();
			termos = TD.values();
			regras = RD.values();
		}

		
		 FileWriter fstream = new FileWriter(fileFolder+nameTxt+".txt");
		 BufferedWriter out = new BufferedWriter(fstream);
		 
		 out.write("FUNCTION_BLOCK " + nameTxt);
		 
		 new2line(out);
		 
		 out.write("VAR_INPUT");
		 out.newLine();
		 
		 for(Object vtemp : variaveis){
			if(((Variaveis) vtemp).getTipo().equals("INPUT")){
				 out.write("	"+((Enum)vtemp).name()+" : REAL;");
				 out.newLine();
		 	}
		 }
		 
		 out.write("END_VAR");
		 
		 new2line(out);
		 
		 out.write("VAR_OUTPUT");
		 out.newLine();
		 for(Object vtemp : variaveis){
			 if(((Variaveis) vtemp).getTipo().equals("OUTPUT")){
				 out.write("	"+((Enum)vtemp).name()+" : REAL;");
				 out.newLine();
		 	}
			 
		 }
		 out.write("END_VAR");
		 new2line(out);
		 
		 for(Object  vtemp : variaveis){
			 if(((Variaveis)vtemp).getTipo().equals("INPUT")){
				 out.write("FUZZIFY "+ ((Enum) vtemp).name());
				 out.newLine();
				 for(Object ttemp : termos){

					 if(((Termos) ttemp).getVariavel().ordinal() == ((Enum) vtemp).ordinal()){
						 out.write("	TERM "+((Enum) ttemp).name()+" := "+((Termos) ttemp).getPoints()+";");
						 out.newLine();
					 }
				 }
				 out.write("END_FUZZIFY");
				 new2line(out);
			 }
			 if(((Variaveis) vtemp).getTipo().equals("OUTPUT")){
				 
				 out.write("DEFUZZIFY "+ ((Enum) vtemp).name());
				 out.newLine();
				 
				 for(Object ttemp : termos){
					 if(((Termos) ttemp).getVariavel().ordinal() == ((Enum) vtemp).ordinal()){
						 out.write("	TERM "+((Enum) ttemp).name()+" := "+((Termos) ttemp).getPoints()+";");
						 out.newLine();
					 }
				 }
				 if(((Enum) vtemp).name().contains("Singleton")){
					 out.write("	METHOD : "+ FuzzySystem.methodSingleTon+";");
				 }
				 else{
					 out.write("	METHOD : "+ FuzzySystem.method+";");
				 }
				 
				 out.newLine();
				 out.write("	DEFAULT := "+ FuzzySystem.de_fault+";");
				 out.newLine();
				 out.write("END_DEFUZZIFY");
				 new2line(out);
			 }
		 }
		 
		 out.write("RULEBLOCK No1");
		 out.newLine();
		 out.write("	AND : " + FuzzySystem.and+";");	
		 out.newLine();
		 out.write("	ACT : " + FuzzySystem.act+";");
		 out.newLine();
		 out.write("	ACCU : " + FuzzySystem.accu+";");
		 out.newLine();
		 if(tipo == FUZZY){
			 int count = 1;
			 for(Object r : regras){
				 
				 Termos input [] = ((Regras)r).getInput();
				 Termos output [] = ((Regras)r).getOutput();
				 String conectivos [] = null;
				 int parenteses [] = null;
				 if(!(((Regras)r).getConectivos()).equals("")){
					 conectivos = ((Regras)r).getConectivos().split(" ");
					 parenteses = new int[conectivos.length];
				 }
				 
				 
				 
				 out.write("	 RULE "+count+" : IF ");
				 count++;
				 String antecedente = "";
				 for(int i = 0 ; i < input.length ; i++){
					 Termos t = input[i];
					 for(Object variavel : variaveis){
						 if(t.getVariavel().ordinal() == ((Enum) variavel).ordinal()){
							 antecedente = antecedente + (((Enum)variavel).name()+".IS."+((Enum)t).name());
							 break;
						 }
					 }
					 
					 if(i+1 != input.length){
						 antecedente = antecedente+" "+( conectivos[i].substring(0, conectivos[i].length()-1))+" ";
						 parenteses[i] = Character.getNumericValue(conectivos[i].charAt(conectivos[i].length() -1));
						 
					 }
				 }
				 if(conectivos != null){
					 antecedente = trataParenteses(antecedente, parenteses);
				 }
				 antecedente = antecedente.replace(".", " ");
				 out.write(antecedente);
				 
				 out.write(" THEN ");
				 for(int i = 0 ; i < output.length ; i++){
					 Termos t = output[i];
					 for(Object variavel : variaveis){
						 if(t.getVariavel().ordinal() == ((Enum) variavel).ordinal()){
							 out.write(((Enum)variavel).name()+" IS "+((Enum)t).name()+" ");
							 break;
						 }
					 }
					 if(i+1 != output.length){
						 out.write(" , ");
					 }
				 }
				 if(((Regras)r).getWeight()!=1){
					 out.write("WITH "+((Regras)r).getWeight());
				 }
				 out.write(";");
				 out.newLine();
			 }
		 }
		 
		 out.write("END_RULEBLOCK");
		 out.newLine();
		 out.write("END_FUNCTION_BLOCK");
		 
		 out.close();
	}
	
	private static String trataParenteses(String antecedente, int [] parenteses){
		
		String[] antecedenteSplit = antecedente.split(" ");
		String saida = "";
		for(int i  = 0 ; i < parenteses.length ; i++){
			if(parenteses[i] != 0){
				
				antecedenteSplit[i*2 +2] = "(" + antecedenteSplit[i*2 +2];
				antecedenteSplit[(i+parenteses[i])*2 +2] = antecedenteSplit[(i+parenteses[i])*2 +2] + ")";
				
			}
		}
		
		for(int i = 0 ; i < antecedenteSplit.length ; i++){
			saida = saida+" "+antecedenteSplit[i]+" ";
		}
		
		return saida;
	}
	
	public static void new2line(BufferedWriter out) throws IOException{
		out.newLine();
		out.newLine();
	}
}
